`include "defines.v"

module mem_wb (
    input wire                              clk,
    input wire                              rst,
    
    input  wire                             stall_i,
    input  wire                             flush_i,

    input  wire[`RAM_ADDR_WIDTH - 1 : 0]    inst_addr_i,
    input  wire[`INST_WIDTH - 1: 0]         inst_i,

    input  wire                             rd_w_ena_i,
    input  wire[4 : 0]                      rd_w_addr_i,
    input  wire[`REG_BUS]                   rd_w_data_i,

    input  wire                             csr_w_ena_i,
    input  wire[11: 0]                      csr_w_addr_i,
    input  wire[`REG_BUS]                   csr_w_data_i,

    input  wire[`REG_BUS]                   exception_type_i,
    input  wire                             valid_i,

    input  wire                             skip_i,

    output reg [`RAM_ADDR_WIDTH - 1 : 0]    inst_addr_o,
    output reg [`INST_WIDTH - 1: 0]         inst_o,

    output reg                              rd_w_ena_o,
    output reg [4 : 0]                      rd_w_addr_o,
    output reg [`REG_BUS]                   rd_w_data_o,

    output reg                              csr_w_ena_o,
    output reg [11: 0]                      csr_w_addr_o,
    output reg [`REG_BUS]                   csr_w_data_o,

    output reg [`REG_BUS]                   exception_type_o,
    output reg                              valid_o,

    output reg                              skip_o
);
    always @(posedge clk) begin
        if(rst == 1'b1) begin
            inst_addr_o         <= 0;
            inst_o              <= 0;

            rd_w_ena_o          <= 1'b0;
            rd_w_addr_o         <= 5'h0;
            rd_w_data_o         <= 64'h0;

            csr_w_ena_o         <= 1'b0;
            csr_w_addr_o        <= 12'h0;
            csr_w_data_o        <= 64'h0;

            exception_type_o    <= `ZERO_WORD;
            valid_o             <= 1'b0;
            skip_o              <= 1'b0;
        end
        else begin
            if(stall_i == 1'b1) begin
                inst_addr_o         <= inst_addr_o;
                inst_o              <= inst_o;

                rd_w_ena_o          <= rd_w_ena_o;
                rd_w_addr_o         <= rd_w_addr_o;
                rd_w_data_o         <= rd_w_data_o;

                csr_w_ena_o         <= csr_w_ena_o;
                csr_w_addr_o        <= csr_w_addr_o;
                csr_w_data_o        <= csr_w_data_o;

                exception_type_o    <= exception_type_o;
                valid_o             <= valid_o;
                
                skip_o              <= skip_o;
            end
            else if(flush_i == 1'b1) begin
                inst_addr_o         <= 0;
                inst_o              <= 0;

                rd_w_ena_o          <= 1'b0;
                rd_w_addr_o         <= 5'h0;
                rd_w_data_o         <= 64'h0;

                csr_w_ena_o         <= 1'b0;
                csr_w_addr_o        <= 12'h0;
                csr_w_data_o        <= 64'h0;

                exception_type_o    <= `ZERO_WORD;
                valid_o             <= 1'b0;
                skip_o              <= 1'b0;
            end
            else begin
                inst_addr_o         <= inst_addr_i;
                inst_o              <= inst_i;

                rd_w_ena_o          <= rd_w_ena_i;
                rd_w_addr_o         <= rd_w_addr_i;
                rd_w_data_o         <= rd_w_data_i;

                csr_w_ena_o         <= csr_w_ena_i;
                csr_w_addr_o        <= csr_w_addr_i;
                csr_w_data_o        <= csr_w_data_i;

                exception_type_o    <= exception_type_i;
                valid_o             <= valid_i;
                skip_o              <= skip_i;
            end
        end
    end
endmodule
